package com.jiantong.web.open.app.work;

import com.google.common.collect.Maps;
import com.jiantong.common.util.UserUtil;
import com.jiantong.user.ext.LoginUser;
import com.jiantong.user.service.BreedFactoryReadService;
import com.jiantong.web.core.enums.ExceptionCode;
import com.jiantong.web.util.SendMessage;
import com.jiantong.work.dto.BreedReportDto;
import com.jiantong.work.enums.BreedReportStatus;
import com.jiantong.work.enums.DocumentsDeleteFlag;
import com.jiantong.work.model.BreedReport;
import com.jiantong.work.model.BreedReportSurveyRecord;
import com.jiantong.work.service.*;
import io.terminus.boot.rpc.common.annotation.RpcConsumer;
import io.terminus.common.model.Paging;
import io.terminus.common.model.Response;
import io.terminus.pampas.openplatform.annotations.OpenBean;
import io.terminus.pampas.openplatform.annotations.OpenMethod;
import io.terminus.pampas.openplatform.exceptions.OPClientException;
import io.terminus.pampas.openplatform.exceptions.OPServerException;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.util.Strings;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMethod;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Created by niufei on 2017/3/15.
 *
 */
@Slf4j
@OpenBean
public class BreedReportApis {

    @RpcConsumer
    private BreedReportReadService breedReportReadService;

    @RpcConsumer
    private BreedReportWriteService breedReportWriteService;

    @RpcConsumer
    private BreedReportSurveyRecordReadService breedReportSurveyRecordReadService;

    @RpcConsumer
    private BreedReportSurveyRecordWriteService breedReportSurveyRecordWriteService;

    @RpcConsumer
    private AnimalCertificateService animalCertificateService;

    @RpcConsumer
    private BreedFactoryReadService breedFactoryReadService;

    @Autowired
    private SendMessage sendMessage;

    @OpenMethod(
            key = "find.breed.report.by.id",
            paramNames = {"id"},
            httpMethods = RequestMethod.GET
    )
    public BreedReport findBreedReportById(Long id){
        if(id == null){
            log.error("id should be not null");
            throw new OPClientException(ExceptionCode.ID_NOT_EXIST.value(),
                    "id should be not null");
        }
        Response<BreedReport> breedReportResponse = breedReportReadService.findById(id);
        if(!breedReportResponse.isSuccess()){
            log.error("failed to find breed report , cause : {}", breedReportResponse.getError());
            throw new OPServerException(ExceptionCode.DATA_NOT_FOUND.value(),
                    breedReportResponse.getError());
        }
        return breedReportResponse.getResult();
    }

    @OpenMethod(
            key = "find.breed.report.status.by.id",
            paramNames = {"id"},
            httpMethods = RequestMethod.GET
    )
    public Map<String ,Integer> findStatusById(Long id){
        if(id == null){
            log.error("id should be not null");
            throw new OPClientException(ExceptionCode.ID_NOT_EXIST.value(),
                    "id should be not null");
        }
        Response< Map<String ,Integer>> response = breedReportReadService.findStatusById(id);
        if(!response.isSuccess()){
            log.error("failed to find breed report status, cause : {}", response.getError());
            throw new OPServerException(ExceptionCode.DATA_NOT_FOUND.value(),
                    response.getError());
        }
        return response.getResult();
    }

    @OpenMethod(
            key = "paging.breed.report",
            paramNames = {"pageNo","pageSize","statuses","breedFactoryId"},
            httpMethods = RequestMethod.GET
    )
    public Paging<BreedReport> pagingBreedReport(Integer pageNo,Integer pageSize,List<Integer> statuses,Long breedFactoryId){

        if(breedFactoryId == null){
            log.error("breedFactoryId should be not null");
            throw new OPClientException(ExceptionCode.ID_NOT_EXIST.value(),
                    "breedFactoryId should be not null");
        }
        Map<String, Object> criteria = Maps.newHashMap();

        criteria.put("breedFactoryId",breedFactoryId);

        if(statuses!=null) {
            criteria.put("statuses",statuses);
        }
        criteria.put("deleteFlag", DocumentsDeleteFlag.NORMAL.value());
        Response<Paging<BreedReport>> pagingResponse = breedReportReadService.pagingBreedReport(pageNo,pageSize,criteria);
        if(!pagingResponse.isSuccess()){
            log.error("failed to paging breed report , cause : {}", pagingResponse.getError());
            throw new OPServerException(ExceptionCode.DATA_NOT_FOUND.value(),
                    pagingResponse.getError());
        }
        return pagingResponse.getResult();
    }

    @OpenMethod(
            key = "create.breed.report",
            paramNames = {"breedReport","toStatus"},
            httpMethods = RequestMethod.POST
    )
    public Map<String , Object> createBreedReport(BreedReport breedReport , Integer toStatus){
        if(breedReport.getStatus() == null){
            log.error("status should be not null");
            throw new OPClientException(ExceptionCode.PARAMETER_NOT_EXIST.value(),"status should be not null");
        }

        if(!breedReport.getStatus().equals(toStatus)&&toStatus != null){
            List<String> markNumbers = breedReport.getEarTagNumbers();
            if(markNumbers == null || markNumbers.isEmpty()){
                log.error("markNumbers should be not null");
                throw new OPClientException(ExceptionCode.PARAMETER_NOT_EXIST.value(),"markNumbers should be not null");
            }
        }
        Response<Map<String , Object>> response = breedReportWriteService.create(breedReport,toStatus);
        if(!response.isSuccess()){
            log.error("failed to create breed report error = {}, cause : {}", breedReport, response.getError());
            throw new OPServerException(ExceptionCode.DATA_WRITE_FAIL.value(),
                    response.getError());
        }
        return response.getResult();
    }

    @OpenMethod(
            key = "update.breed.report",
            paramNames = {"breedReport" , "toStatus"},
            httpMethods = RequestMethod.PUT
    )
    public Map<String , Object> updateBreedReport(BreedReport breedReport, Integer toStatus){

        if(breedReport.getId() == null){
            log.error("failed to update breed report error = {}, cause : {}", breedReport,breedReport.getId());
            throw new OPClientException(ExceptionCode.ID_NOT_EXIST.value(),
                    "breed.report.id.is.null");
        }

        if(breedReport.getStatus() == null){
            log.error("status should be not null");
            throw new OPClientException(ExceptionCode.PARAMETER_NOT_EXIST.value(),"status should be not null");
        }

        if(!breedReport.getStatus().equals(toStatus)&&toStatus != null){
            List<String> markNumbers = breedReport.getEarTagNumbers();
            if(markNumbers == null || markNumbers.isEmpty()){
                log.error("markNumbers should be not null");
                throw new OPClientException(ExceptionCode.PARAMETER_NOT_EXIST.value(),"markNumbers should be not null");
            }
        }

        Response<Map<String , Integer>> mapResponse = breedReportReadService.findStatusById(breedReport.getId());
        if(mapResponse.isSuccess() && !mapResponse.getResult().get("status").equals(breedReport.getStatus())){
            log.error("breed report is already submitted error = {}, cause : {}", breedReport.getStatus(),mapResponse.getResult().get("status"));
            throw new OPClientException(ExceptionCode.DOCUMENT_REPEAT_SUBMIT.value(),
                    "this.report.is.already.submitted");
        }
        Response<Map<String , Object>> response = breedReportWriteService.update(breedReport,toStatus);
        if(!response.isSuccess()){
            log.error("failed to update breed report error = {}, cause : {}", breedReport, response.getError());
            throw new OPServerException(ExceptionCode.DATA_WRITE_FAIL.value(),
                    response.getError());
        }
        return response.getResult();
    }

    @OpenMethod(
            key = "find.breed.report.and.survey.record.by.id",
            paramNames = {"id"},
            httpMethods = RequestMethod.GET
    )
    public BreedReportDto findBreedReportAndSurveyRecordByReportId(Long id){
        if(id == null){
            log.error("id should be not null");
            throw new OPClientException(ExceptionCode.ID_NOT_EXIST.value(),
                    "id should be not null");
        }
        BreedReportDto breedReportDto = new BreedReportDto();
        Response<BreedReport> reportResponse = breedReportReadService.findById(id);
        if(!reportResponse.isSuccess()){
            log.error("failed to find breedReport by id = {}, cause : {}", id, reportResponse.getError());
            throw new OPServerException(ExceptionCode.DATA_NOT_FOUND.value(),
                    reportResponse.getError());
        }
        breedReportDto.setBreedReport(reportResponse.getResult());
        Long surveyRecordId = breedReportSurveyRecordReadService.findIdByReportId(id);
        if(surveyRecordId != null){
            Response<BreedReportSurveyRecord> reportSurveyRecordResponse = breedReportSurveyRecordReadService.findByReportId(id);
            if(!reportSurveyRecordResponse.isSuccess()){
                log.error("failed to find breedReportSurveyRecord by id = {}, cause : {}", id, reportSurveyRecordResponse.getError());
                throw new OPServerException(ExceptionCode.DATA_NOT_FOUND.value(),
                        reportSurveyRecordResponse.getError());
            }

            breedReportDto.setBreedReportSurveyRecord(reportSurveyRecordResponse.getResult());
        }else{
            breedReportDto.setBreedReportSurveyRecord(new BreedReportSurveyRecord());
        }
        return Response.ok(breedReportDto).getResult();
    }

    @OpenMethod(
            key = "save.breed.report.and.survey.record",
            paramNames = {"breedReport","breedReportSurveyRecord","toStatus"},
            httpMethods = RequestMethod.POST
    )
    public Map<String, Object> saveBreedReportAndSurveyRecord(BreedReport breedReport,
                                                              BreedReportSurveyRecord breedReportSurveyRecord,
                                                              Integer toStatus){


        //todo 加上角色的判断

        //判断主键id是否存在
        if(breedReport.getId() == null){
            log.error("id should be not null");
            throw new OPClientException(ExceptionCode.ID_NOT_EXIST.value(),
                    "id should be not null");
        }
        //判断单据是否已经被提交过了
        Response<Map<String , Integer>> mapResponse = breedReportReadService.findStatusById(breedReport.getId());
        if(mapResponse.isSuccess() && !mapResponse.getResult().get("status").equals(breedReport.getStatus())){
            log.error("breed report is already submitted error = {}, cause : {}", breedReport.getStatus(),mapResponse.getResult().get("status"));
            throw new OPClientException(ExceptionCode.DOCUMENT_REPEAT_SUBMIT.value(),
                    "this.report.is.already.submitted");
        }
        if(!toStatus.equals(BreedReportStatus.SURVEYED.value())
                && !breedReport.getStatus().equals(BreedReportStatus.STAY_APPROVE.value())
                && breedReportSurveyRecord.getId()==null){
            log.error("failed to update breedReportSurveyRecord error = {}, cause : {}",
                    breedReportSurveyRecord,breedReportSurveyRecord.getId());
            throw new OPClientException(ExceptionCode.ID_NOT_EXIST.value(),
                    "breed.report.survey.record.id.is.null");
        }
        Response<Map<String,Object>> response = breedReportSurveyRecordWriteService.save(breedReport,breedReportSurveyRecord,toStatus);

        if(!response.isSuccess()){
            log.error("failed to save breedReportSurveyRecord and breedReport error = {}, cause : {}",
                    breedReportSurveyRecord,breedReport, response.getError());
            throw new OPServerException(ExceptionCode.DATA_WRITE_FAIL.value(),
                    response.getError());
        }
        if(toStatus.equals(BreedReportStatus.STAY_LICENSE.value())){
            String number = breedReport.getNumber();
            sendMessage.sendMsg(breedReport.getOwner(),number.substring(number.length()-9),breedReport.getCertificateStationName(),breedReport.getOwnerMobile());
        }

        return response.getResult();
    }

    @OpenMethod(
            key = "paging.breed.report.multi",
            paramNames = {"pageNo","pageSize","statuses","breedFactoryId","fromDate","toDate","isScale"},
            httpMethods = RequestMethod.GET
    )
    public Paging<BreedReport> pagingMulti(Integer pageNo,Integer pageSize,
                                           List<Integer> statuses, Long breedFactoryId,
                                           String fromDate , String toDate,
                                           Integer isScale){
        Date start = null;
        if(!Strings.isNullOrEmpty(fromDate)){
            start = DateTime.parse(fromDate).toDate();
        }
        Date end = null;
        if(!Strings.isNullOrEmpty(toDate)){
            end = DateTime.parse(toDate).toDate();
        }
        Response<Paging<BreedReport>> pagingResponse = breedReportReadService.pagingMulti(pageNo,pageSize,statuses,breedFactoryId,start,end,isScale);
        if(!pagingResponse.isSuccess()){
            log.error("failed to paging breed report , cause : {}", pagingResponse.getError());
            throw new OPServerException(ExceptionCode.DATA_NOT_FOUND.value(),
                    pagingResponse.getError());
        }
        return pagingResponse.getResult();
    }

    @OpenMethod(
            key = "paging.breed.report.multi.gf",
            paramNames = {"pageNo","pageSize","statuses","applyReportId","certificateStationId","fromDate","toDate","isScale"},
            httpMethods = RequestMethod.GET
    )
    public Paging<BreedReport> pagingMultiGF(Integer pageNo,Integer pageSize,
                                           List<Integer> statuses, Long applyReportId,Long certificateStationId,
                                           String fromDate , String toDate,
                                           Integer isScale){
        Date start = null;
        if(!Strings.isNullOrEmpty(fromDate)){
            start = DateTime.parse(fromDate).toDate();
        }
        Date end = null;
        if(!Strings.isNullOrEmpty(toDate)){
            end = DateTime.parse(toDate).toDate();
        }
        Response<Paging<BreedReport>> pagingResponse = breedReportReadService.pagingMultiGF(pageNo,pageSize,statuses,applyReportId,certificateStationId,start,end,isScale);
        if(!pagingResponse.isSuccess()){
            log.error("failed to paging breed report , cause : {}", pagingResponse.getError());
            throw new OPServerException(ExceptionCode.DATA_NOT_FOUND.value(),
                    pagingResponse.getError());
        }
        return pagingResponse.getResult();
    }

    @OpenMethod(
            key = "paging.for.veterinarian",
            paramNames = {"pageNo","pageSize","statuses"},
            httpMethods = RequestMethod.GET
    )
    public Paging<BreedReport> pagingForVeterinarian(Integer pageNo,Integer pageSize,List<Integer> statuses){
        LoginUser loginUser = UserUtil.getCurrentUser();

        List<Long> breedFactoryIds = loginUser.getBreedFactoryIds();
        Response<List<Long>> response = breedFactoryReadService.selectIds(breedFactoryIds);
        if(!response.isSuccess()){
            log.error("failed to select ids");
            throw new OPServerException(ExceptionCode.DATA_NOT_FOUND.value(),response.getError());
        }
        breedFactoryIds = response.getResult();
        if(breedFactoryIds == null || breedFactoryIds.isEmpty()){
            return new Paging<>(0L,new ArrayList<BreedReport>());
        }
        Response<Paging<BreedReport>> pagingResponse =
                breedReportReadService.pagingForVeterinarian(pageNo,pageSize,breedFactoryIds,statuses);
        if(!pagingResponse.isSuccess()){
            log.error("failed to paging breed report , cause : {}", pagingResponse.getError());
            throw new OPServerException(ExceptionCode.DATA_NOT_FOUND.value(),
                    pagingResponse.getError());
        }

        return pagingResponse.getResult();
    }
}
